/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.model;

import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;

/**
 *
 * @author Walter Lütgenau
 */
public class ServerModel implements Server {

    URL serviceUrl;
    private static String userName = null; // for debugging
    private static String password = null; // for debugging

    /**
     * Creates a new instance of UploadModel
     */
    public ServerModel(URL serviceUrl) {
        this.serviceUrl = serviceUrl;
    }

    public static void setPassword(String password) {
        ServerModel.password = password;
    }

    public static String getPassword() {
        return password;
    }

    public static void setUserName(String userName) {
        ServerModel.userName = userName;
    }

    public static String getUserName() {
        return userName;
    }

    public static String getAuthenticationParameters() {
        if (userName == null)
            return null;
        return "userName=" + getUserName() + "&password=" + getPassword();
    }

    public Serializable sendRequest(Serializable request) throws Exception {
        if (ServerModel.userName != null) // for debugging only
            enableDebugging(request);

        ByteArrayOutputStream requestStream = new ByteArrayOutputStream(512);
        ObjectOutputStream requestObjectStream = new ObjectOutputStream(requestStream);
        requestObjectStream.writeObject(request);
        requestObjectStream.flush();

        URLConnection connection = serviceUrl.openConnection();
        connection.setRequestProperty("Content-Length", String.valueOf(requestStream.size()));
        connection.setRequestProperty("Content-Type", "application-x-java-serialized-object");
        connection.setDoOutput(true);

        OutputStream out = connection.getOutputStream();
        requestStream.writeTo(connection.getOutputStream());
        out.close();

        // unbelievable but true: You need to read and ignore the (here not existing) reply to get your output stream being flushed.
        ObjectInputStream in = new ObjectInputStream(connection.getInputStream());
        Serializable response = (Serializable) in.readObject();
        connection.getInputStream().close();

        if (response instanceof ExceptionResponse) {
            ExceptionResponse exception = (ExceptionResponse) response;
            ExceptionService.alert(exception.getTitle(), exception.getMessage(), exception.getSeverity());
            throw new Exception(exception.getMessage()); // to avoid class cast exception
        }

        return response;
    }

    /**
     * This is an extension only for debugging purposes.
     * 
     * Update the user requests with the user credentials as set for debugging.
     * 
     * @param request the server request
     */
    private void enableDebugging(Serializable request) {
        if (!(request instanceof UserRequest)
                && !(request instanceof CollectionRequest))
            return;


        if (request instanceof CollectionRequest) {
            Iterator<ServerRequest> requests = ((CollectionRequest) request).getServerRequests();
            while (requests.hasNext()) {
                enableDebugging(requests.next());
            }
            
            return;
        }        
        
        UserRequest urequest = (UserRequest) request;
        if ((urequest.getUserName() == null || urequest.getUserName().length() == 0)) {
            urequest.setUserName(ServerModel.userName);
            urequest.setPassword(ServerModel.password);
        }

    }

    public URL getURL() {
        return serviceUrl;
    }
}
